package tests;

import static org.junit.Assert.assertEquals;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runners.JUnit4;

import pico.picoScannerParser.PicoParser;
import pico.picoScannerParser.PicoScanner;
import pico.picoScannerParser.PicoToken;

/**
 * This class is a {@link JUnit4} testcase used for testing the {@link PicoScanner}
 * 
 * @author Sander Meijer & Bart Wentink
 *
 */
public class PicoTest {
	
	PicoScanner scanner;
	static PicoParser parser;
	String dataStructure = "TestFiles/EBNF_scanner/EBNF_4";
	
	@BeforeClass
	public static void beforeClass() {
		parser = new PicoParser(false);
	}
	
	@Test
	public void scannerTest_1(){
		assertEquals(
				"BEGIN " +
					"PRINT 'H' + 'e' + 'l' + 'l' + 'o' + ' ' + 'w' + 'o' + 'r' + 'l' + 'd' " +
				"END ",
				scanFile("TestFiles/pico_scanner/pico_1"));
	}
	
	@Test
	public void scannerTest_2(){
		assertEquals(
				"BEGIN " +
					"DO " +
						"GETAL_1 = 7 , " +
						"GETAL_2 = 7 , " +
						"PRINT getal_1 * getal_2 , " +
						"PRINT ( getal_1 + getal_2 ) * ( getal_1 * getal_2 ) " +
					"OD " +
				"END ", 
				scanFile("TestFiles/pico_scanner/pico_2"));
	}
	
	@Test
	public void correctParseTest_1(){
		assertEquals(
				"BEGIN " +
					"PRINT 'H' + 'e' + 'l' + 'l' + 'o' + ' ' + 'w' + 'o' + 'r' + 'l' + 'd' " +
				"END ",
				parser.parse(dataStructure, "TestFiles/pico_scanner/pico_1"));
	}
	
	@Test
	public void correctParseTest_2(){
		assertEquals(
				"BEGIN INT getal_1 : 8 , " +
					"INT getal_2 : 12 , " +
					"INT uitkomst , " +
					"BOOL print : true " +
					"DO " +
						"uitkomst = getal_1 + getal_2 , " +
						"IF print THEN " +
							"PRINT uitkomst " +
						"ELSE " +
							"PRINT 'N' + 'i' + 'e' + 't' + ' ' + 'p' + 'r' + 'i' + 'n' + 't' + 'e' + 'n' " +
						"FI " +
					"OD " +
				"END ",
				parser.parse(dataStructure, "TestFiles/pico_scanner/pico_3"));
	}

	@Test(expected = RuntimeException.class)
	public void incorrectParseTest_1(){
		assertEquals("BEGIN " +
						"INT getal = 8 " +
						"PRINT getal " +
					"END ", 
				parser.parse(dataStructure, "TestFiles/pico_scanner/pico_4"));
	}

	@Test(expected = RuntimeException.class)
	public void incorrectParseTest_2() {
		parser.parse(dataStructure, "TestFiles/pico_scanner/pico_5");
	}
	
	@Test
	public void correctControle_1(){
		assertEquals(
				"BEGIN INT getal_1 : 8 , " +
					"INT getal_2 : 12 , " +
					"INT uitkomst , " +
					"BOOL print : true " +
					"DO " +
						"uitkomst = getal_1 + getal_2 , " +
						"IF print THEN " +
							"PRINT uitkomst " +
						"ELSE " +
							"PRINT 'N' + 'i' + 'e' + 't' + ' ' + 'p' + 'r' + 'i' + 'n' + 't' + 'e' + 'n' " +
						"FI " +
					"OD " +
				"END ",
				parser.parse(dataStructure, "TestFiles/pico_scanner/pico_3"));
	}
	
	@Test
	public void correctControle_2(){
		assertEquals("" +
				"BEGIN " +
					"BOOL parseable : true , " +
					"INT getal_1 : 1 , " +
					"INT getal_2 : 2 , " +
					"INT getal_3 : 3 , " +
					"INT getal_4 : 4 , " +
					"BOOL firstbool : false , " +
					"BOOL secondbool : true , " +
					"INT anothernumber : 1 , " +
					"INT undeclarednumber , " +
					"BOOL thirdbool : true , " +
					"BOOL undeclaredbool , " +
					"INT thirdnumber : 9 , " +
					"INT secondundeclarednumber " +
					"undeclarednumber = 9 , " +
					"PRINT getal_3 , " +
					"undeclaredbool = true " +
				"END ",
		parser.parse(dataStructure, "TestFiles/pico_scanner/pico_6"));
	}
	
	@Test
	public void correctControle_3(){
		assertEquals("" +
				"BEGIN " +
					"INT getal_1 : 9 , " +
					"INT getal_2 : 12 , " +
					"BOOL allowed : true " +
					"DO " +
						"IF allowed THEN " +
							"DO " +
								"PRINT getal_1 + getal_2 + getal_1 , " +
								"allowed = false " +
							"OD " +
						"ELSE " +
							"allowed = true " +
						"FI " +
					"OD " +
				"END ",
		parser.parse(dataStructure, "TestFiles/pico_scanner/pico_8"));
	}
	
	@Test(expected = RuntimeException.class)
	public void incorrectControle_1(){
		assertEquals(
				"BEGIN " +
					"DO " +
						"GETAL_1 = 7 , " +
						"GETAL_2 = 7 , " +
						"PRINT getal_1 * getal_2 , " +
						"PRINT ( getal_1 + getal_2 ) * ( getal_1 * getal_2 ) " +
					"OD " +
				"END ", 
				parser.parse(dataStructure, "TestFiles/pico_scanner/pico_2"));

	}
	
	@Test(expected = RuntimeException.class)
	public void incorrectControle_2(){
		assertEquals("BEGIN " + 
				"BOOL true_bool : true" +
				"IF true_bool THEN " + 
					"PRINT truth " +
				"FI " +
			"END ", parser.parse(dataStructure, "TestFiles/pico_scanner/pico_7"));
	}
	


	/**
	 * Returns a string with the text of the scanned tokens.
	 * @param {@link String} pathname
	 * @return {@link String} textTokens
	 */
	private String scanFile(String pathname){
		String output = "";
		try {
			FileInputStream fis = new FileInputStream(new File(pathname));
			this.scanner = new PicoScanner(fis);
			
			PicoToken token = scanner.nextToken();	
			while(token != null){
				output += token.getText() + " ";
				token = scanner.nextToken();
			} 
			
		} catch (FileNotFoundException e) {
			System.out.println("There is no file here.");
			e.printStackTrace();
		} catch (IOException e) {
			System.out.println("IO except");
			e.printStackTrace();
		}
		return output;
	}
}
